package com.mobile.check.present;

import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import cn.droidlover.xdroidmvp.kit.Kits;
import cn.droidlover.xdroidmvp.kit.NLog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import com.mobile.check.activitys.TaskItemListActivity;
import com.mobile.check.beans.TaskInfo;
import com.mobile.check.beans.TaskItemInfo;
import com.mobile.check.db.EntityManager;
import com.mobile.check.util.CrashHandler;
import com.mobile.check.util.DoubleUtil;
import com.mobile.check.util.ExcelUtils;
import com.mobile.check.util.ExportLeakPointUtil;

/**
 * 类名: TaskDetailPresent
 * 作者: 李学伟
 * 日期: 2020年10月09日 13:40
 * 描述:
 */
public class TaskDetailPresent extends BasePresent<TaskItemListActivity> {

    Handler handler;
    boolean allowExport = true;

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    public void getTaskItems(final TaskInfo info) {
        Observable.just(info).map(new Function<TaskInfo, List<TaskItemInfo>>() {
            @Override
            public List<TaskItemInfo> apply(TaskInfo taskInfo) throws Exception {
                List dataList = EntityManager.getInstance().queryTaskItemInfoByParentId(taskInfo.get_ID());
                return dataList;
            }
        }).map(new Function<List<TaskItemInfo>, List<TaskItemInfo>>() {
            List<String> labelList = new ArrayList<>();

            @Override
            public List<TaskItemInfo> apply(List<TaskItemInfo> taskItemInfos) throws Exception {
                Iterator<TaskItemInfo> iterator = taskItemInfos.iterator();
                while (iterator.hasNext()) {
                    TaskItemInfo itemInfo = iterator.next();
                    String equment = itemInfo.getEquipment();
                    String label = itemInfo.getLabel();
                    String area = itemInfo.getArea();
                    String key = area + equment + label;
                    if (labelList.contains(key)) {
                        EntityManager.getInstance().delTaskItemInfo(itemInfo);
                        NLog.d(key + " 重复了");
                        iterator.remove();
                    } else {
                        labelList.add(key);
                    }
                }

                return taskItemInfos;
            }
        }).subscribe(new Consumer<List<TaskItemInfo>>() {
            @Override
            public void accept(List<TaskItemInfo> list) throws Exception {
                parserExcelSuccess(info, list);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                throwable.printStackTrace();
                getV().showTipDialog("文件解析失败", "我知道了", true);
            }
        });
    }

    public void getTaskItems(final TaskInfo info, final String searchContent) {
        Observable.just(info).map(new Function<TaskInfo, List<TaskItemInfo>>() {
            @Override
            public List<TaskItemInfo> apply(TaskInfo taskInfo) throws Exception {
                List dataList = EntityManager.getInstance().queryTaskItemInfoByParentId(taskInfo.get_ID(), searchContent);
                return dataList;
            }
        }).map(new Function<List<TaskItemInfo>, List<TaskItemInfo>>() {
            List<String> labelList = new ArrayList<>();

            @Override
            public List<TaskItemInfo> apply(List<TaskItemInfo> taskItemInfos) throws Exception {
                Iterator<TaskItemInfo> iterator = taskItemInfos.iterator();
                while (iterator.hasNext()) {
                    TaskItemInfo itemInfo = iterator.next();
                    String equment = itemInfo.getEquipment();
                    String label = itemInfo.getLabel();
                    String area = itemInfo.getArea();
                    String key = area + equment + label;
                    if (labelList.contains(key)) {
                        iterator.remove();
                    } else {
                        labelList.add(key);
                    }
                }

                return taskItemInfos;
            }
        }).subscribe(new Consumer<List<TaskItemInfo>>() {
            @Override
            public void accept(List<TaskItemInfo> list) throws Exception {
                getV().onSuccess(true, list);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                throwable.printStackTrace();
            }
        });
    }

    private void parserExcelSuccess(TaskInfo info, List<TaskItemInfo> list) {
        int testNum = 0;
        int falNum = 0;
        for (TaskItemInfo itemInfo : list) {
            String testValue;
            if (info.getTaskType() == 0) {//检测任务
                testValue = itemInfo.getTestValue();
            } else if (info.getTaskType() == 1) {
                testValue = itemInfo.getRepeatValue();
            } else {
                testValue = itemInfo.getTestValue();
            }
            String leakValue = itemInfo.getLeakValue();
            if (itemInfo.getLabel().equals("1030.019")) {
                NLog.d("TaskDetailPresent", "testValue=" + testValue);
                NLog.d("TaskDetailPresent", "leakValue=" + leakValue);
            }

            if (!TextUtils.isEmpty(testValue) && !TextUtils.isEmpty(leakValue)) {
                try {
                    if (Float.valueOf(testValue) >= Float.valueOf(leakValue)) {
                        falNum++;
                        itemInfo.setIsQualified(true);
                    } else {
                        itemInfo.setIsQualified(false);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }


            if (itemInfo.isHadTest()) {
                testNum++;
            }
        }
        getV().parserSuccess(testNum, falNum, list);
    }

    String logName;
    Disposable exportDisposable;

    public void startSaveToFile(final TaskInfo taskInfo) {
        allowExport = true;
        logName = "保存日志";
        saveLog(logName, "开始导出数据", true);

        createTargetDir(taskInfo.getTaskFilePath());
        exportDisposable = Observable.just(taskInfo).map(new Function<TaskInfo, List<TaskItemInfo>>() {
            @Override
            public List<TaskItemInfo> apply(@NonNull TaskInfo taskInfo) throws Exception {
                final String exportFilePath = createNewXlsxFile(taskInfo.getTaskFilePath());
                taskInfo.setExportFilePath(exportFilePath);
                return writeToXlsx(taskInfo);
            }
        }).map(new Function<List<TaskItemInfo>, List<Integer>>() {
            @Override
            public List<Integer> apply(List<TaskItemInfo> leakList) throws Exception {
                saveLog(logName, "泄漏点数量1=" + leakList.size());
                List<Integer> leakIndexList;
                if (leakList.size() != 0) {
                    leakIndexList = createLeakPicOrder(leakList);
                } else {
                    leakIndexList = new ArrayList<>();
                }
                return leakIndexList;
            }
        }).map(new Function<List<Integer>, Boolean>() {
            @Override
            public Boolean apply(@NonNull List<Integer> leakList) throws Exception {
                saveLog(logName, "泄漏点数量2=" + leakList.size());
                if (!allowExport) {
                    return false;
                }
                if (leakList.size() != 0) {
                    leakList.add(0, 0);
                    return saveLeakToFile(taskInfo, leakList);
                } else {
                    return true;
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Exception {
                if (aBoolean) {
                    Log.d("TaskDetailPrsent", "成功");
                    getV().showTipDialog("成功", "我知道了", true);
                } else {
                    getV().showTipDialog("失败", "我知道了", true);
                }

            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                Log.d("TaskDetailPrsent", "失败");
                throwable.printStackTrace();
                saveLog(logName, CrashHandler.getInstance().getCrashInfo(throwable));
                getV().showTipDialog("失败", "我知道了", false);
            }
        });

    }

    public List<TaskItemInfo> writeToXlsx(TaskInfo taskInfo) throws IOException, InvalidFormatException {
        saveLog(logName, "开始将数据库内容写入到文件");
        List<TaskItemInfo> dataList = EntityManager.getInstance().queryTaskItemInfoByParentId(taskInfo.get_ID());
        List<TaskItemInfo> leakList = new ArrayList<>();
        FileInputStream inputStream = null;
        FileOutputStream fileOut = null;
        Workbook workbook;
        try {
            inputStream = new FileInputStream(taskInfo.getExportFilePath());
            workbook = ExcelUtils.createworkbook(inputStream);
            fileOut = new FileOutputStream(taskInfo.getExportFilePath());
            int count = 0;
            for (TaskItemInfo itemInfo : dataList) {

                count++;
                Message message = new Message();
                message.obj = "监测点存储中(" + count + "/" + dataList.size() + ")";
                handler.sendMessage(message);
                if (TextUtils.isEmpty(itemInfo.getTestValue()) && TextUtils.isEmpty(itemInfo.getRepeatValue())) {
                    continue;
                }

                if (taskInfo.getTaskType() == 0 && (isLeak(itemInfo.getLeakValue(), itemInfo.getTestValue()) || isLeak(itemInfo.getLeakValue(), itemInfo.getRepeatValue()))) {
                    leakList.add(itemInfo);
                }
                saveDataToRow(workbook, taskInfo, itemInfo);
                if (!allowExport) {
                    break;
                }
            }
            workbook.write(fileOut);
            fileOut.flush();
            Kits.File.copyFile(taskInfo.getExportFilePath(), taskInfo.getTaskFilePath());
            saveLog(logName, "写入到文件成功");
        } catch (Exception ex) {
            saveLog(logName, "写入到文件异常");
            saveLog(logName, CrashHandler.getInstance().getCrashInfo(ex));
            throw ex;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (null != fileOut) {
                    fileOut.close();
                }
            } catch (Exception ex) {
                saveLog(logName, "关闭流异常");
                saveLog(logName, CrashHandler.getInstance().saveCrashInfo2File(ex));
                ex.printStackTrace();
            }
        }

        return leakList;

    }

    private void saveDataToRow(Workbook workbook, TaskInfo taskInfo, TaskItemInfo itemInfo) {
        saveLog(logName, "开始导入点");
        saveLog(logName, new Gson().toJson(itemInfo));
        Sheet sheet = workbook.getSheetAt(0);// 获取第一个表
        // 如果已有行、列直接获取
        Map<Integer, Object> valueMap = getFillExcelMap(itemInfo, taskInfo.getTaskType());
        if (valueMap.size() == 0) {
            saveLog(logName, "保存信息為空22");
        } else {
            saveLog(logName, "開始保存信息");
            Row row = sheet.getRow(itemInfo.getRowIndex());// 得到行
            for (Integer integer : valueMap.keySet()) {

                Object valueObj = valueMap.get(integer);
                if (null == valueObj) {
                    continue;
                }
                Cell cell = row.getCell(integer);
                if (null == cell) {
                    NLog.d("TaskItemCheckPresent", integer + " 为空");
                    cell = row.createCell(integer);
                }
                setCell(workbook, cell, valueObj);
                if (!allowExport) {
                    break;
                }
            }
        }
    }


    private void setCell(Workbook workbook, Cell cell, Object value) {

        CellStyle cellStyle = cell.getCellStyle();
        int cellType = cell.getCellType();
//        NLog.d("setCell", "cellStyle=" + cellStyle);
//        NLog.d("setCell", "cellType=" + cellType);
        if (null == cellStyle) {
            cellStyle = workbook.createCellStyle();
            cell.setCellStyle(cellStyle);
        }
        String fmt = cellStyle.getDataFormatString();
//        NLog.d("setCell", "fmt=" + fmt);
        DataFormat format = workbook.createDataFormat();
        if (value instanceof String) {
//            NLog.d("setCell", "String-" + value);
            cell.setCellValue(String.valueOf(value));
        } else if (value instanceof Integer) {
            cell.setCellValue((int) value);
        } else if (value instanceof Double) {
            cellStyle.setDataFormat((short) 0);
            cell.setCellValue((double) value);
        } else if (value instanceof Boolean) {
//            NLog.d("setCell", "Boolean-" + value);
            cell.setCellValue((boolean) value);
        } else if (value instanceof Date) {
            CellStyle dateStyle = workbook.createCellStyle();
            dateStyle.cloneStyleFrom(cellStyle);
            dateStyle.setDataFormat(format.getFormat("yyyy/M/dd HH:mm:ss"));
//            NLog.d("setCell", "Date-" + value);
            cellStyle = dateStyle;
            cell.setCellValue((Date) value);
        } else {
            cell.setCellValue(value.toString());
        }
        cell.setCellStyle(cellStyle);
    }

    private Map<Integer, Object> getFillExcelMap(TaskItemInfo itemInfo, int taskType) {
        Map<Integer, Object> valueMap = new HashMap<>();
        Double testValue;
        Double backValue;
        Double realValue;
        SimpleDateFormat ymdhms2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

        String leakValueStr = itemInfo.getLeakValue();
        double leakValue;
        try {
            leakValue = Double.parseDouble(leakValueStr);
        } catch (Exception e) {
            leakValue = 0d;
            e.printStackTrace();
        }
        switch (taskType) {
            case 0:
                try {
                    Date date = ymdhms2.parse(itemInfo.getTestDate());
                    valueMap.put(9, date);
                } catch (ParseException e) {
                    e.printStackTrace();
                    valueMap.put(9, itemInfo.getTestDate());
                }

                valueMap.put(10, itemInfo.getTestDevice());
                testValue = DoubleUtil.getDouble(itemInfo.getTestValue(), 1);
                backValue = DoubleUtil.getDouble(itemInfo.getBackGround(), 1);

//                realValue = testValue - backValue;
                realValue = testValue + backValue;//检测值最终结果为 实际检测值 + 背景值
                realValue = DoubleUtil.getDouble(realValue, 1);
                if (realValue < 0) {
                    realValue = 0d;
                }
                valueMap.put(11, realValue);
                if (isLeak(itemInfo.getLeakValue(), itemInfo.getTestValue())) {
                    valueMap.put(12, Double.valueOf("1"));
                    valueMap.put(13, itemInfo.getLeakLocation());
                } else {
                    valueMap.put(12, Double.valueOf("0"));
                    valueMap.put(13, "");
                }


                valueMap.put(14, backValue);
                valueMap.put(17, 0);
                valueMap.put(18, itemInfo.getTestPerson());
                break;
            case 1:


                try {
                    Date date = ymdhms2.parse(itemInfo.getRepeatDate());
                    valueMap.put(15, date);
                } catch (ParseException e) {
                    e.printStackTrace();
                    valueMap.put(15, itemInfo.getRepeatDate());
                }


                valueMap.put(16, itemInfo.getRepeatDevice());

                testValue = DoubleUtil.getDouble(itemInfo.getRepeatValue(), 1);
                backValue = DoubleUtil.getDouble(itemInfo.getBackGround(), 1);

                realValue = testValue + backValue;
                if (realValue <= 0) {
                    realValue = 0d;
                }
                realValue = DoubleUtil.getDouble(realValue, 1);
                valueMap.put(17, realValue);
//                valueMap.put(17, itemInfo.getRepeatValue());
                valueMap.put(18, backValue);
                valueMap.put(21, itemInfo.getRepeatPerson());
                break;
            case 2:

                try {
                    Date date = ymdhms2.parse(itemInfo.getTestDate());
                    valueMap.put(10, date);
                } catch (ParseException e) {
                    e.printStackTrace();
                    valueMap.put(10, itemInfo.getTestDate());
                }
                valueMap.put(11, itemInfo.getTestDevice());
                testValue = DoubleUtil.getDouble(itemInfo.getTestValue(), 1);
                backValue = DoubleUtil.getDouble(itemInfo.getBackGround(), 1);

                realValue = testValue + backValue;
//                realValue = testValue;
                if (realValue <= 0) {
                    realValue = 0d;
                }
                realValue = DoubleUtil.getDouble(realValue, 1);
                valueMap.put(12, realValue);

                if (isLeak(itemInfo.getLeakValue(), itemInfo.getTestValue())) {
                    valueMap.put(13, Double.valueOf("1"));
                    valueMap.put(14, itemInfo.getLeakLocation());
                } else {
                    valueMap.put(13, Double.valueOf("0"));
                    valueMap.put(14, "");
                }

//                valueMap.put(12, itemInfo.getTestValue());
                valueMap.put(15, backValue);
                valueMap.put(16, itemInfo.getTestPerson());
                break;
        }
        return valueMap;
    }

    /**
     * 生成维修工单
     */
    private List<Integer> createLeakPicOrder(List<TaskItemInfo> leakList) {
        saveLog(logName, "开始生成泄维修工单");
        ExportLeakPointUtil leakPointUtil = new ExportLeakPointUtil(getV());
        List<Integer> leakIndexList = new ArrayList<>();
        int count = 0;
        for (TaskItemInfo itemInfo : leakList) {
            count++;
            Message message = new Message();
            message.obj = "正在生成维修工单(" + count + "/" + leakList.size() + ")";
            handler.sendMessage(message);
            leakPointUtil.startExport(itemInfo, targetDir);
            leakIndexList.add(itemInfo.getRowIndex());
            if (!allowExport) {
                break;
            }
        }
        return leakIndexList;
    }


    private boolean saveLeakToFile(TaskInfo taskInfo, List<Integer> leakList) {
        Message message = new Message();
        message.obj = "正在整理泄漏点!";
        handler.sendMessage(message);

        saveLog(logName, "开始保存泄漏点信息");
//        ExcelUtils excelUtils = new ExcelUtils();
        final String fileName = Kits.File.getFileName(taskInfo.getExportFilePath());
//        FileInputStream inputStream;
//        Workbook workbook = null;
        boolean result = true;
        try {
//            inputStream = new FileInputStream(taskInfo.getExportFilePath());
//            workbook = ExcelUtils.createworkbook(inputStream);
            String targetFilePath = targetDir + "泄漏点" + File.separator + fileName;
            ExcelUtils.createLeakFile(taskInfo.getExportFilePath(), targetFilePath, leakList);
//            excelUtils.init(targetDir, fileName);
//            excelUtils.copySheet(workbook, leakList);
        } catch (Exception e) {
            saveLog(logName, "开始保存泄漏点信息");
            e.printStackTrace();
            result = false;
        }
        return result;

    }

    String targetDir;

    private void createTargetDir(String sourceFilePath) {
        String sRoot = Environment.getExternalStorageDirectory().getAbsolutePath();//获取跟目录
        StringBuilder tarDirBuilder = new StringBuilder(sRoot);
        tarDirBuilder.append(File.separator).append("检测系统/数据导出/")
                .append(Kits.File.getFileNameWithoutExtension(sourceFilePath))
                .append(File.separator);
        targetDir = tarDirBuilder.toString();
        Kits.File.deleteFile(targetDir);

        Kits.File.makeFolders(targetDir);
        saveLog(logName, "创建文件夹");
        saveLog(logName, targetDir);
    }

    private String createNewXlsxFile(String sourceFilePath) {
        saveLog(logName, "复制原文件到导出文件夹");
        File file = new File(sourceFilePath);
        File newFile = new File(targetDir, file.getName());
        if (newFile.exists()) {
            newFile.delete();
        }
        Kits.File.copyFile(sourceFilePath, newFile.getPath());
        return newFile.getPath();
    }

    public void stopExport() {
        allowExport = false;
        if (null != exportDisposable && !exportDisposable.isDisposed()) {
            exportDisposable.dispose();
            Kits.File.deleteFile(targetDir);
        }
    }

    public boolean isAllowExport() {
        return allowExport;
    }

    public boolean isLeak(String leakValueStr, String testValueStr) {

        try {
            double leakValue = Double.parseDouble(leakValueStr);
            double testValue = Double.parseDouble(testValueStr);
            return testValue >= leakValue;
        } catch (Exception ex) {
            return false;
        }


    }
}


